<?php
/**
 * 页面搜索
 */
class Search_Client 
{
	const _CONST_URL_PREFIX_   = '/s/';
	const _CONST_SORT_DEFAULT_ = 99;

	private static $_instance  = NULL;

	private $_raw_query_string = NULL;
	private $_sphinx           = NULL;
	private $_query_type, $_query, $_query_orig_key;
	private $_alias_key, $_alias_class;
	private $_sphinx_result;
	private $_search_limit, $_search_page;
	private $_multiple_char;
	private $_category_highlights = NULL;

	/**
	 * 当前搜索的别称
	 *
	 */
	public static function current_alias ()
	{
		$alias = self::instance()->query_alias();
		if (empty($alias))
			return self::instance()->alias_from_query_class();
		else
			return $alias;
	}

	public static function instance()
	{
		if (self::$_instance === NULL)
		{
			$class = __CLASS__;
			$query = Request::initial()->param('search');
			self::$_instance = new $class($query);
		}

		return self::$_instance;
	}

	private function __construct ($query_string)
	{
		$this->_raw_query_string = $query_string;
		$this->_sphinx   = new Search_Sphinx;
		$this->build_query ();
	}

	public function page_limit ($type = 'goods')
	{
		if ($type == 'goods')
			return Arr::get($this->_query, 'limit', Kohana::config('search.limit.default'));
		else if ($type == 'cuxiao')
			return Kohana::config('search.limit.cuxiao');
		else if ($type == 'pc')
			return Kohana::config('search.limit.pc');
		else
			return Arr::get($this->_query, 'limit', Kohana::config('search.limit.shop'));
	}

	public function query_type  ()
	{
		return $this->_query_type;
	}

	public function query_alias ()
	{
		return $this->_alias_key;
	}


	public function query_sort ()
	{
		return Arr::get($this->_query, 'sort', self::_CONST_SORT_DEFAULT_);
	}

	public function query ($key, $default = NULL)
	{
		return Arr::get($this->_query, $key, $default);
	}

	public function province_list ()
	{
		return City::get_province_list();
	}

	public function city_list ()
	{
		$prov = $this->query('province');
		if (empty($prov))
			return array();
		else
			return City::get_city_list((int) $prov);
	}

	public function search_goods ()
	{
		$query =& $this->_query;

		$sort_by = Arr::get($query, 'sort', 2);
		$key     = Arr::get($query, 'key',  '');
		$limit   = Arr::get($query, 'limit', Kohana::config('search.limit.default'));
		$page    = max(1, Arr::get($query, 'page', 1));
		$offset  = ($page - 1) * $limit;
		$this->_search_limit = $limit;
		$this->_search_page  = $page;
		$cond    = $this->build_sphinx_param ();

		$this->_sphinx_result = $this->_sphinx->get_search_result($key, $cond, $sort_by, $limit, $offset);
		return $this->_sphinx_result;
	}
	
	public function search_cuxiao ()
	{
		$query =& $this->_query;

		$sort_by = Arr::get($query, 'sort', 1);
		$key     = Arr::get($query, 'key',  '');
		$limit   = Arr::get($query, 'limit', Kohana::config('search.limit.cuxiao'));
		$page    = max(1, Arr::get($query, 'page', 1));
		$offset  = ($page - 1) * $limit;
		$this->_search_limit = $limit;
		$this->_search_page  = $page;
		$cond    = $this->build_sphinx_param ();

		$this->_sphinx_result = $this->_sphinx->get_search_result($key, $cond, $sort_by, $limit, $offset);
		return $this->_sphinx_result;
	}
	
	public function search_pc()
	{
		$query =& $this->_query;
		
		$key     = Arr::get($query, 'key');
		$limit   = Arr::get($query, 'limit', Kohana::config('search.limit.pc'));
		$page    = max(1, Arr::get($query, 'page', 1));
		$offset  = ($page - 1) * $limit;
		$this->_search_limit = $limit;
		$this->_search_page  = $page;
		$cond    = array('key' => $key);
		$pc_search = new Pingce_search();
		$this->_sphinx_result = $pc_search->search($cond,$offset,$limit);
		
		return $this->_sphinx_result;
	}

	public function search_shop ()
	{
		$query =& $this->_query;
		$cond  = $this->build_shop_sphinx_param();
		
		$limit   = Arr::get($query, 'limit', Kohana::config('search.limit.shop'));
		$page    = max(1, Arr::get($query, 'page', 1));
		$offset  = ($page - 1) * $limit;
		$this->_search_limit = $limit;
		$this->_search_page  = $page;
		$this->_sphinx_result = $this->_sphinx->get_shop_list($cond, $limit, $offset);
		return $this->_sphinx_result;
	}




	/**
	 * 生成导航信息列表：当前搜索分类为末级，上溯到顶级分类的数组
	 *
	 * @return	array
	 */
	public function navigator_items ()
	{
		$category = $this->query('class');
		$alias    = $this->query_alias();

		// 别名搜索时的导航列表为空(临时)
		if (! empty($alias))
		{
			$name = Kohana::config('search.pattern.alias.'.$alias.'.name');
			return array(array('name' => $name));
		}

		// 非别名搜索时是搜索分类的家族树
		if (!empty($category))
		{
			$category_ids = Category_System::parent_ids($category);
			$category_info = array();
			$pid           = 0;
			foreach ($category_ids as $item)
			{
				$category_info[$item]['name'] = & Category_System::name($item);
				$category_info[$item]['url']  = $this->link(array('class' => $item));
				$category_info[$item]['pid']  = $pid;
				$pid = $item;
			}
			Category_System::commit_names();
			return $category_info;
		}

		return NULL;
	}
	
	/**
	 * 生成导航的品牌
	 */
	public function navigator_brand()
	{
		$brand = $this->query('brand');
		if (!empty($brand))
		{
			$brand_info = Category_brand::brand_infos(array($brand));
			return $brand_info;
		}
		return NULL;
	}
	
	/**
	 * 生成导航的地区
	 */
	public function navigator_location()
	{
		$location = $this->query('location');
		if (!empty($location))
		{
			$location_name = City::county_name($location);
			if (empty($location_name))
				$location_name = City::shangquan_name($location);
			$result = array(
				'id' => $location,
				'name' => $location_name,
			);
			return $result;
		}
		return NULL;
	}

	/**
	 * 根据搜索环境返回末级分类下的和价格有关的属性列表
	 *
	 * @return	array
	 */
	public function price_attrs ()
	{
		$cateogry_id = $this->query('class', 0);
		$attrs       = array();

		if ($cateogry_id > 0)
			$attrs = Category_Attr::pv_names($cateogry_id, NULL, 1);
		if ($attrs === NULL)
			$attrs = array();

		$attrs_array = array();
		foreach ($attrs as $key=>$item)
		{
			if (isset($item['type']) && $item['type'] == 'price')
			{
				$attrs_array[$key] = $item;
			}
		}

		return $attrs_array;
	}
		

	/**
	 * 根据搜索环境和提供的参数生成搜索地址
	 *
	 * @param	array	$q
	 * @param	array	$exclude
	 * @return	string	$url
	 */
	public function link ($q = NULL, $exclude = NULL)
	{
		$uri = '';
		$query = $this->_query;
		// 取消城市
		unset($query['city']);

		if (!empty($q) && !isset($q['page']))
			$q['page'] = NULL;

		if (!empty($this->_query_orig_key))
			$query['key'] = $this->_query_orig_key;

		if (is_array($exclude))
			foreach ($exclude as $ek)
				$q[$ek] = NULL;

		if (!empty($q))
		{
			foreach ($q as $k => $v)
			{
				if (NULL === $v)
					unset($query[$k]);
				else
					$query[$k] = $v;
			}
		}

		foreach ($query as $k1 => $v1)
		{
			$uri .= '/' . $k1 . '/' . (is_array($v1) ?  
							join($this->_multiple_char, $v1) : 
							rawurlencode($v1));
		}

		return self::_CONST_URL_PREFIX_.$this->_query_type.$uri. Kohana::config('search.pattern.suffix');
	}

	/**
	 * 生成sphinx的商品搜索参数
	 *
	 */
	private function build_sphinx_param ($class = NULL)
	{
		$query =& $this->_query;

		if ($class !== NULL)
			$result['category'] = 'c'.$class;
		else if (isset($query['class']))
			$result['category'] = 'c'.$query['class'];
		else if (! empty($this->_alias_class))
		{
			foreach ($this->_alias_class as $cid)
				$classes[] = 'c'.$cid;
			$result['category'] = implode('|', $classes);
		}

		if (isset($query['pv']) && !empty($query['pv']))
		{
			$vid_ps = Category_Attr_PVS::prop_ids($query['pv']);
			$pvs    = array();
			foreach ($vid_ps as $vid => $pid)
			{
				$pvs[] = 'k'.$pid.'v'.$vid;
			}

			$result['prop'] = implode(' ', $pvs);
		}

		if (isset($query['brand']) && !empty($query['brand']))
			$result['brand'] = $query['brand'];
			
		if (isset($query['location']) && !empty($query['location']))
			$result['location'] = $query['location'];
			
		if (isset($query['city']) && !empty($query['city']))
			$result['city'] = $query['city'];
			
		if (isset($query['auth']) && !empty($query['auth']))
			$result['auth'] = $query['auth'];

		return $result;
	}

	/**
	 * 生成sphinx的商铺搜索参数
	 *
	 */
	private function build_shop_sphinx_param()
	{
		$query =& $this->_query;
		$key   = Arr::get($query, 'key');

		if (! empty($key))
			$result['kword'] = $query['key'];

		if (isset($query['class']) && !empty($query['class']))
			$result['category'] = $query['class'];
		if (isset($query['type']) && !empty($query['type']))
			$result['shop_type'] = $query['type'];
		if (isset($query['province']) && !empty($query['province']))
			$result['province'] = $query['province'];
		if (isset($query['city']) && !empty($query['city']))
			$result['city'] = $query['city'];
			
		return $result;
	}

	/**
	 * 返回当前搜索环境里分类下的品牌(有商品的)列表
	 *
	 */
	public function category_brands ()
	{
		$cid = $this->query('class');
		$kword = $this->query('key');

		if ($cid > 0)
		{
			$brandsearch = new Category_brandsearch();
			return $brandsearch->get_brand_by_category($cid, 'goods');
		}
		else if (! empty($this->_alias_class))
		{
			$brandsearch = new Category_brandsearch();
			$cids =& $this->_alias_class;
			$brands = array();
			foreach ($cids as $cid)
			{
				$arr = $brandsearch->get_brand_by_category($cid, 'goods');
				foreach ($arr as & $brand)
				{
					$bid = $brand['brand_id'];
					if (! isset($brands[$bid]))
						$brands[$bid] = $brand;
				}
			}

			if (!empty($brands))
				return $brands;
			else
				return Kohana::config('search.system_brands');
		}
		else
			return NULL;
	}

	/**
	 * 当前搜索的关键词是否品牌名称
	 *
	 * @return boolean
	 */
	public function key_is_brand_name ($kword)
	{
		return FALSE;
	}

	public function brand_info_by_key ()
	{
		return NULL;
	}
	
	/**
	 * 返回搜索的分类结果中当前的父级分类和当前分类
	 *
	 */
	public function category_highlights ()
	{
		if (is_array($this->_category_highlights))
			return $this->_category_highlights;
		else
			return array(0, 0);
	}

	/**
	 * 根据当前搜索环境返回分类列表
	 *
	 */
	public function category_list ()
	{
		$root_cid  = $this->query('class');
		$key       = $this->query('key');
		$cate_list = NULL;

		$cate_list = $this->get_categories ($root_cid, $this->_query_type);
		$info  = Category_System::info($root_cid);
		$this->_category_highlights = array(
				'id'   => $root_id,
				'name' => $info['cate_name'],
		);
		
// 		if (empty($cate_list))
// 			$cate_list = $this->get_categories (0, $this->_query_type);

		//
		// 补充分类列表里的分类点击地址
		//
		$this->build_category_link ($cate_list);

		return $cate_list;
	}

	/**
	 * 返回系统分类列表
	 *
	 */
	public function get_system_category()
	{
		// 获取一级系统分类
		$cate_sys		= new Category_System();
		$syscategory1	= $cate_sys->get_strict_list(0, $this->_query_type);

		$syscategory = array();
		if(empty($syscategory1))
			return false;

		foreach($syscategory1 as $key => & $val)
		{
			$syscategory[$key] = array(
				'cate1' => array(
					'id'		=> $val['id'],
					'cate_name'	=> $val['cate_name'],
				),
			);

			$syscategory[$key]['cate2'] = $cate_sys->get_strict_list($val['id'], $this->_query_type);	
			$syscategory[$key]['brand_info'] = Category_Brand::get_by_category_level($val['id'],1);
		}
		
		$this->filter_top_category_list ($syscategory);
		return $syscategory;
	}

	/**
	 * 某分类CID下的分类列表
	 *
	 * @param	int		$cid
	 * @param	string	$foreight_key = ['goods', 'shops']
	 * @return	array
	 */
	private function get_categories ($cid = 0, $foreigh_status = NULL)
	{
		$cates = array();

		// 
		// 定向别名搜索使用预定义顶级分类
		// 
		if (empty($cid))
		{
			if (! empty($this->_alias_class))
			{
				$sys  = new Category_System;
				foreach ($this->_alias_class as $acid)
				{
					$arr = $sys->get_strict_list($acid, $foreigh_status);	
					if (is_array($arr))
						$cates = array_merge($cates, $arr);
				}
			}
			else
				return $this->get_system_category();
		}
		else
		{
			$sys  = new Category_System;
// 			$c_info = $sys->info($cid);
// 			if ($c_info['is_leaf'] == 1)
// 				$cid = $sys->parent_id($cid);
			$cates= $sys->get_strict_list($cid, $foreigh_status);
		}

		$cate_list = array();
		foreach ($cates as $item)
		{
			$cate_list[$item['id']] = array(
				'cate1' => array('id' => $item['id'], 'cate_name' => $item['cate_name']),);
		}
		
		return $cate_list;
	}

	/**
	 * 返回根据商品搜索结果里的商品所在的分类
	 *
	 * @return array	$list
	 * @return NULL if failure
	 */
	private function get_goods_categories (& $goods_ids)
	{
		if (empty($goods_ids))
			return NULL;

		$ids   = $goods_ids;
		$class = $this->query('class');
		$level = Category_System::level($class);
		if ($level >= 2)
		{
			$parent_cids = Category_System::parent_ids($class);
			$parent_cid  = empty($parent_cids) ? 0 : $parent_cids[1];
			$ids = $this->goods_ids_in_class (Category_System::parent_id($parent_cid));
			if (empty($ids))
				return NULL;
		}

		$query = array(
			'select' => array('cs.cate_2', 'cs.cate_3', 'cs.cate_name'),
			'id'     => $ids,
			'enable_search_count' => FALSE,
			'format_results'      => FALSE,
			'join_category_sys'   => TRUE,
		);

		$result = Goods::search($query);
		if (empty($result['list']))
			return NULL;

		$cates = array();
		$cids  = array();
		foreach ($result['list'] as $l)
		{
			$c2 = $l['cate_2'];
			$c3 = $l['cate_3'];

			if ($c2 <= 0)
				continue;

			if (! isset($cates[$c2]))
				$cates[$c2] = array();

			if ($c3 > 0 AND ! in_array($c3, $cates[$c2]))
				$cates[$c2][] = $c3;

			$cids[] = $c2;
			$cids[] = $c3;
		}

		$cids = array_unique($cids);
		$names= category_system::names ($cids);

		$cate_list = array();
		foreach ($cates as $cid => $arr)
		{
			$cate_list[$cid] = array(
				'cate1' => array('id' => $cid, 'cate_name' => $names[$cid]),
			);

			$crr = array();
			foreach ($arr as $c)
				$crr[$c] = array('id' => $c, 'cate_name' => $names[$c]);

			$cate_list[$cid]['cate2'] = $crr;
		}

		return $cate_list;
	}


	/**
	 * 针对所有顶级系统分类做过滤和排序
	 */
	private function filter_top_category_list (& $list)
	{
		$ls = array();
		$forbidden = Kohana::config('search.category_top.forbidden');
		$orders    = Kohana::config('search.category_top.orders');

		foreach ($list as $cate)
		{
			$cid = $cate['cate1']['id'];
			if (! in_array($cid, $forbidden) && !empty($cate['brand_info'])) 
				$ls[$cid] = $cate;
		}

		$result = array();

		foreach ($orders as $id)
		{
			if (isset($ls[$id]))
			{
				$result[] = $ls[$id];
				unset($ls[$id]);
			}
		}

		foreach ($ls as $item)
			$result[] = $item;

		$list = $result;
	}

	/**
	 * 为分类列表数据补充链接地址
	 */
	private function build_category_link (& $cate_list)
	{
		$exclude = array('sort', 'pv', 'brand');
		if (is_array($cate_list))
		{
			foreach ($cate_list as & $item1)
			{
				$item1['cate1']['link'] = $this->link (array('class' => $item1['cate1']['id']), $exclude);
			}
		}
	}


	/**
	 * 从搜索字符串转换搜索条件
	 */
	private function build_query ()
	{
		$pattern_multiple = Kohana::config('search.pattern.multiple');
		$multiple_char    = Kohana::config('search.pattern.multiple_char');
		$pattern_types    = Kohana::config('search.pattern.types');
		$pattern_suffix   = Kohana::config('search.pattern.suffix');
		$pattern_alias    = Kohana::config('search.pattern.alias');
		$query_type       = Kohana::config('search.pattern.type_default');
		$alias_key        = NULL;
		$this->_multiple_char = $multiple_char;

		$items   = explode('/', strtolower(rtrim(trim($this->_raw_query_string, '/'), $pattern_suffix)));
		$query   = array();

		//
		// query type
		//
		if (count($items) > 0 && in_array($items[0], $pattern_types))
		{
			$query_type = array_shift($items);
		}
		else if (count($items) > 0 && in_array($items[0], array_keys($pattern_alias)))
		{
			$alias_key  = array_shift($items);
			$query_type = $pattern_alias[$alias_key]['type'];
		}

		$patterns = Kohana::config('search.pattern.'.$query_type);

		//
		// query condition
		//
		for ($i = 0; $i < count($items); $i += 2)
		{
			$k = $items[$i + 0];
			$v = $items[$i + 1];
			if (in_array($k, $patterns))
			{
				if (in_array($k, $pattern_multiple))
					$query[$k] = explode($multiple_char, trim($v));
				else
					$query[$k] = trim($v);
			}
		}

		if (!empty($alias_key))
			$this->_alias_class = $pattern_alias[$alias_key]['class'];

		if ($query_type == 'cuxiao')
		{
			$city_id = City::current_id();
			$query['city'] = $city_id;
		}
		$this->_query_type = $query_type;
		$this->_alias_key  = $alias_key;
		$this->_query      = $query;
		$this->pinyin_2_chinese ();
		return array(empty($alias_key) ? $query_type : $alias_key, $query);
	}

	private function alias_from_query_class ()
	{
		$class = $this->query('class');
		if (empty($class))
			return NULL;

		$cids = Category_System::parent_ids ($class);
		$cid  = Arr::get($cids, 0);
		if (empty($cid))
			return NULL;
		else
		{
			$alias_configs = Kohana::config('search.pattern.alias');
			foreach ($alias_configs as $key => & $config)
			{
				if (in_array($cid, $config['class']))
					return $key;
			}

			return NULL;
		}
	}

	/**
	 * 当前搜索环境下覆盖默认分类下的商品ID列表
	 *
	 */
	private function goods_ids_in_class ($class_id)
	{
		$env = $this->build_sphinx_param ($class_id);
		$key = $this->query('key', NULL);

		// 无必要设置，需要kongjian修改
		$sort  = $this->query_sort();
		$limit = 800;		
		$offset= 0;
		return $this->_sphinx->get_goods_ids($key, $env, $sort, $limit, $offset);
	}

	private function pinyin_2_chinese()
	{
		$key = Arr::get($this->_query, 'key');
		if (! empty($key))
		{
			$chinese = $this->ascii_2_chinese ($key);
			if (!empty($chinese))
			{
				$this->_query['key']   = $chinese;
				$this->_query_orig_key = $key;
			}
		}
	}

	private function ascii_2_chinese ($pinyin)
	{
		$p = new Search_Word;
		return $p->pinyin_2_chinese ($pinyin);
	}
}
